package org.ym.basic;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.stereotype.Component;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * ApplicationContext管理器
 * @author ym
 * @date 2022-06-09 22:22:38
 */
@Component
public class AppUtils implements ApplicationContextAware, ServletContextListener {

    private AppUtils(){}

    public static final String SLASH = "/";
    /**
     * ApplicationContext
     */
    private static  ApplicationContext applicationContext;
    /**
     * ServletContext
     */
    private static ServletContext servletContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        AppUtils.applicationContext = applicationContext;
    }

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        servletContext = sce.getServletContext();
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        servletContext = null;
    }

    /**
     * 获取spring上下文
     * @return 对象
     */
    public static ApplicationContext getContext(){
        return applicationContext;
    }

    /**
     * 根据类从spring上下文获取bean。
     * @param cls 类型
     * @return 实例
     */
    public static <C> C getBean(Class<C> cls){
        return applicationContext.getBean(cls);
    }

    /**
     * 根据类名从spring上下文获取bean。
     * @param beanId beanId
     * @return 实例
     */
    public static Object getBean(String  beanId){
        return applicationContext.getBean(beanId);
    }

    /**
     * Spring发布事件。
     * @param applicationEvent 事件
     */
    public static void publishEvent(ApplicationEvent applicationEvent){
        applicationContext.publishEvent(applicationEvent);
    }

    /**
     * 根据指定的接口或基类获取实现类列表。
     * @param clazz 类型
     * @return 集合
     * @throws ClassNotFoundException 错误
     */
    public static <T> List<Class<T>> getImplClass(Class<T> clazz){
        List<Class<T>> list=new ArrayList<>();
        Map<String,T> map= getImplInstance(clazz);
        for(T obj : map.values()){
            list.add((Class<T>) obj.getClass());
        }
        return list;
    }

    /**
     * 获取接口的实现类实例。
     * @param clazz 类型
     * @return Map
     */
    public static <T> Map<String, T> getImplInstance(Class<T> clazz){
        return applicationContext.getBeansOfType(clazz);
    }

    /**
     * 取得应用程序的绝对路径
     * @return 路径
     */
    public static String getAppAbsolutePath(){
        return servletContext.getRealPath(SLASH);
    }

    /**
     * 在web环境中根据web页面的路径获取对应页面的绝对路径。
     * @param path 路径
     * @return 路径
     */
    public static String getRealPath(String path){
        return servletContext.getRealPath(path);
    }
}
